#include "udpwork.h"
#include "utils.h"
#include <QNetworkInterface>
#include <QTime>
#include "MessageErrorException.h"
#include "socketwork.h"

UDPWork::UDPWork(QObject *parent) : QObject(parent)
{
    udp_socket = new QUdpSocket(this);
    udp_socket->bind(localAddress, 12345);
    connect(udp_socket, &QUdpSocket::readyRead, this, &UDPWork::receive_data_slot);
}

void UDPWork::send_Broadcast_slot()
{
    try
    {
        send_broadCast();
     }
    catch (const std::exception& e)
    {
        emit update_textBrowser_signal(QString::fromUtf8(e.what()));
    }

}

void UDPWork::send_Message_slot(QString meg)
{
    try
    {
       send_commamd(meg);
    }
    catch (const std::exception& e)
    {
        emit update_textBrowser_signal(QString::fromUtf8(e.what()));
    }

}

void UDPWork::send_broadCast()
{
    QByteArray send_bytes;
    QByteArray header_bytes;

    header_bytes.append(char(0x00));
    header_bytes.append(char(0xff));
    header_bytes.append(char(0x0f));
    header_bytes.append(char(0x00));

    QByteArray total_length_bytes = Number2Bytes<int>(MSG_TYPE_LENGTH);
    QByteArray type_bytes = Number2Bytes<int>(ServerMsgType::ServerSendShakeHand);

    send_bytes.append(header_bytes);
    send_bytes.append(total_length_bytes);
    send_bytes.append(type_bytes);

    udp_socket->writeDatagram(send_bytes, send_bytes.size(), QHostAddress::Broadcast, 24510);
}

void UDPWork::send_commamd(QString command)
{
    QByteArray send_bytes;

    QByteArray command_bytes = command.toLocal8Bit();

    QByteArray header_bytes;

    header_bytes.append(char(0x00));
    header_bytes.append(char(0xff));
    header_bytes.append(char(0x0f));
    header_bytes.append(char(0x00));

    QByteArray total_length_bytes = Number2Bytes<int>(command_bytes.length() + MSG_TYPE_LENGTH + MSG_STREAM_LENGTH);
    QByteArray type_bytes = Number2Bytes<int>(ServerMsgType::ServerSendCommand);
    QByteArray command_length_bytes = Number2Bytes<int>(command_bytes.length());

    send_bytes.append(header_bytes);
    send_bytes.append(total_length_bytes);
    send_bytes.append(type_bytes);
    send_bytes.append(command_length_bytes);
    send_bytes.append(command_bytes);

    udp_socket->writeDatagram(send_bytes, remoteAddress , 24510);
}

void UDPWork::send_Recvshakehands(QString ip)
{
    QByteArray send_bytes;

    QByteArray command_bytes = ip.toLocal8Bit();

    QByteArray header_bytes;

    header_bytes.append(char(0x00));
    header_bytes.append(char(0xff));
    header_bytes.append(char(0x0f));
    header_bytes.append(char(0x00));

    QByteArray total_length_bytes = Number2Bytes<int>(command_bytes.length() + MSG_TYPE_LENGTH + MSG_STREAM_LENGTH);
    QByteArray type_bytes = Number2Bytes<int>(ServerMsgType::ServerReceiveShakeHand);
    QByteArray command_length_bytes = Number2Bytes<int>(command_bytes.length());

    send_bytes.append(header_bytes);
    send_bytes.append(total_length_bytes);
    send_bytes.append(type_bytes);
    send_bytes.append(command_length_bytes);
    send_bytes.append(command_bytes);

    udp_socket->writeDatagram(send_bytes, remoteAddress , 24510);
}

void UDPWork::receive_data_slot()
{
    while (udp_socket->hasPendingDatagrams())
    {
        QByteArray datagram;
        datagram.resize(udp_socket->pendingDatagramSize());

        udp_socket->readDatagram(datagram.data(), datagram.size(), &remoteAddress);

        try
        {
           const int index = unpack_receive_data(datagram);
           if (index > 0)
           {
               receive_bytes.remove(0, index);
           }
        }
         catch (MessageErrorException &)
        {
           receive_bytes.clear();
           emit update_textBrowser_signal("Receive Message Header error, auto disconnect socket");
        }
    }
}

int UDPWork::unpack_receive_data(const QByteArray &receive_bytes)
{
    int index = 0;

    while (true)
    {
        if (index + MSG_HEADER_LENGTH + MSG_TOTAL_LENGTH + MSG_TYPE_LENGTH > receive_bytes.length())
        {
            break;
        }
        else
        {
            QByteArray msg_header = receive_bytes.mid(index, MSG_HEADER_LENGTH);

            if (static_cast<unsigned char>(msg_header.at(0)) != 0x00 ||
                static_cast<unsigned char>(msg_header.at(1)) != 0xff ||
                static_cast<unsigned char>(msg_header.at(2)) != 0x0f ||
                static_cast<unsigned char>(msg_header.at(3)) != 0x00)
            {
                throw MessageErrorException(-1);
            }

            int msg_length = Bytes2Number<int>(receive_bytes.mid(index + MSG_HEADER_LENGTH, MSG_TOTAL_LENGTH));

            if (msg_length + index + MSG_HEADER_LENGTH + MSG_TOTAL_LENGTH > receive_bytes.length())
            {
                break;
            }

            ClientMsgType msg_type = ClientMsgType(
                Bytes2Number<int>(receive_bytes.mid(index + MSG_HEADER_LENGTH + MSG_TOTAL_LENGTH, MSG_TYPE_LENGTH)));

            QByteArray msg_data = receive_bytes.mid(index + MSG_HEADER_LENGTH + MSG_TOTAL_LENGTH + MSG_TYPE_LENGTH,
                                                    msg_length - MSG_TYPE_LENGTH);

            index += msg_length + MSG_HEADER_LENGTH + MSG_TOTAL_LENGTH;

            if (msg_type == ClientReceiveShakeHand)
            {
                handle_Recvshakehand_message(msg_data);
            }
            else if (msg_type == ClientSendShakeHand)
            {
                handle_shakehand_message();

            }
            else if(msg_type == ClientSendCommand)
            {
                handle_Command_message(msg_data);
            }
            else if (msg_type == ClientSendPreview)
            {
                handle_preview_message(msg_data);
            }

        }
    }

    return index;
}

void UDPWork::handle_preview_message(const QByteArray &bytes)
{

    int message_length = Bytes2Number<int>(bytes.mid(0, 4));

    QByteArray message_bytes = bytes.mid(4, message_length);
    QPixmap pixmap;

    emit update_textBrowser_signal(QString().number(bytes.length()));

    if (!pixmap.loadFromData(message_bytes))
    {
        return;
    }

    emit preview_image_signal(pixmap.copy());
}

void UDPWork::handle_Command_message(const QByteArray &bytes)
{
    int len = Bytes2Number<int>(bytes.mid(0, 4));
    QString meg = QString(bytes.mid(4, len));

    emit update_textBrowser_signal(meg);
}

void UDPWork::handle_Recvshakehand_message(const QByteArray &bytes)
{
    int len = Bytes2Number<int>(bytes.mid(0, 4));
    QString remoteIP = QString(bytes.mid(4, len));

    emit detain_ClientIP_signal(remoteIP);
    remoteAddress = QHostAddress(remoteIP);

}

void UDPWork::handle_shakehand_message()
{
    emit detain_ClientIP_signal(remoteAddress.toString());

    send_Recvshakehands(GetLocalIP());
}

void UDPWork::Update_IP_slot(QString ip)
{
    localIP = ip;
}

QString UDPWork::GetLocalIP()
{
    QVector<QString> ipv4_vec;

    foreach (QHostAddress ptr, QNetworkInterface::allAddresses())
    {
        if (ptr.protocol() == QAbstractSocket::IPv4Protocol)
        {
            if (!ptr.isLoopback())
            {
                ipv4_vec.append(ptr.toString());
            }
        }
    }

    if (ipv4_vec.empty())
    {
        return "";
    }

    return ipv4_vec.at(0);
}
